package com.cloudkinto.service.doorpick.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cloudkinto.common.common.DateUtils;
import com.cloudkinto.common.constant.SysConstant;
import com.cloudkinto.common.exception.BizException;
import com.cloudkinto.common.utils.OrderCodeUtil;
import com.cloudkinto.common.utils.StringsUtil;
import com.cloudkinto.common.utils.dict.StaticDict;
import com.cloudkinto.dao.*;
import com.cloudkinto.entity.*;
import com.cloudkinto.service.dic.vo.DicItemRes;
import com.cloudkinto.service.doorpick.OrderDoorPickService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.cloudkinto.common.web.PageResult;
import com.cloudkinto.common.web.SingleResult;

import com.cloudkinto.service.doorpick.vo.*;
import com.cloudkinto.service.operate.OperateRecordService;
import com.cloudkinto.service.operate.vo.OperateRes;
import com.cloudkinto.service.quote.QuotePriceService;
import com.cloudkinto.service.quote.vo.QuotePriceRes;
import com.cloudkinto.service.region.JpRegionService;
import com.cloudkinto.service.shipprice.ShipPriceService;
import com.cloudkinto.service.shop.ShopService;
import com.cloudkinto.service.storage.StorageService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * service实现类
 * </p>
 *
 * @author hua
 * @since 2024-03-14
 */
@Service
@Transactional(rollbackFor = Exception.class)
@RequiredArgsConstructor
public class OrderDoorPickServiceImpl extends ServiceImpl<OrderDoorPickDao, OrderDoorPickDo> implements OrderDoorPickService {
    private final JpRegionService regionService;
    private final OperateRecordService operateRecordDao;
    private final OrderDoorPickProductDao orderDoorPickProductDao;
    private final ShopService shopService;
    private final StorageService storageService;
    private final ShopDao shopDao;
    private final StorageDao storageDao;
    private final CompanyDao mCompanyDao;
    private final ProductInfoDao productInfoDao;
    private final OrderOutputDao orderOutputDao;
    private final OrderOutputProductDao orderOutputProductDao;
    private final QuotePriceService quotePriceService;
    private final JpRegionService mRegionService;
    private final ShipPriceService mShipPriceService;

    public String checkPostCode(String postCode) {
        if (!StringUtils.isNotBlank(postCode)) {
            return StringsUtil.createI18Message(SysConstant.OrderOutput_Check_PostCode);
        } else if (postCode.length() != 7) {
            if ((postCode.contains("-") && postCode.length() == 8)) {
            } else {
                return StringsUtil.createI18Message(SysConstant.OrderOutput_Check_CodeForm);
            }
        }
        return null;
    }

    @Override
    public Object add(OrderDoorPickAddReq req, Long userId, Long companyId) {
        if (companyId == null) {
            throw new BizException(SysConstant.Login_Error_Company);
        }
        if (req.getList() == null || req.getList().size() == 0) {
            throw new BizException(SysConstant.No_Data);
        }
        String value = checkPostCode(req.getPostCode());
        if (value != null) {
            throw new BizException(value);
        }
        req.setPostCode(StringsUtil.checkPostCode(req.getPostCode()));
        OrderDoorPickDo entityDo = new OrderDoorPickDo();
        BeanUtils.copyProperties(req, entityDo);
        entityDo.setCompanyId(companyId);
        handlerAddBefore(entityDo, userId);
        JpRegionDo regionDo = regionService.getRegionDoByPostCode(req.getPostCode());
        if (regionDo != null) {
            entityDo.setArea(regionDo.getName());
        }
        entityDo.setBookDate(DateUtils.stringFormatToDate(req.getBookDate()));
        baseMapper.insert(entityDo);
        operateRecordDao.operateAddRecord(SysConstant.OPERATE_CREATE_ORDER_DOOR, entityDo.getId(), userId, 10);
        double[] sizeTemp = new double[4];
        //再去插入 产品信息
        for (OrderOutProductMsgRes productMsgRes : req.getList()) {
            OrderDoorPickProductDo orderDoorPickProductDo = new OrderDoorPickProductDo();
            BeanUtils.copyProperties(productMsgRes, orderDoorPickProductDo);
            orderDoorPickProductDo.setDoorId(entityDo.getId());
            orderDoorPickProductDo.setCreateBy(userId);
            orderDoorPickProductDo.setCreateTime(new Date());
            orderDoorPickProductDao.insert(orderDoorPickProductDo);
            sizeTemp = mShipPriceService.countSameSkuSizeNew(
                    sizeTemp,
                    orderDoorPickProductDo.getLength(),
                    orderDoorPickProductDo.getWidth(),
                    orderDoorPickProductDo.getHeight(),
                    orderDoorPickProductDo.getWeight(),
                    orderDoorPickProductDo.getCount()
            );

        }
        entityDo.setDoorNo(OrderCodeUtil.getOrderDoorNumber(entityDo.getId()));
        this.setPrice(entityDo, sizeTemp);
        baseMapper.updateById(entityDo);
        return null;
    }

    /**
     * 做新增之前要执行的业务定制处理
     */
    private void handlerAddBefore(OrderDoorPickDo entityDo, Long userId) {
        entityDo.setCreateBy(userId);
        entityDo.setCreateTime(new Date());
        entityDo.setDeleteFlag(SysConstant.DELETE_FLAG_FALSE);
    }

    @Override
    public Object update(OrderDoorUpdateReq req, Long userId, Long companyId) {
        if (req.getList() == null || req.getList().size() == 0) {
            throw new BizException(SysConstant.No_Data);
        }
        OrderDoorPickDo et = baseMapper.selectById(req.getId());
        if (et == null) {
            throw new BizException(SysConstant.No_Data);
        }
        if (!Objects.equals(companyId, et.getCompanyId())) {
            throw new BizException(SysConstant.NoPower);
        }
        if (!(StaticDict.Order_Door_Pick_Status.ToCheck.getValue().equals(et.getStatus()))) {
            throw new BizException(SysConstant.NoPower);
        }
        String value = checkPostCode(req.getPostCode());
        if (value != null) {
            throw new BizException(value);
        }
        req.setPostCode(StringsUtil.checkPostCode(req.getPostCode()));
        BeanUtils.copyProperties(req, et);
        JpRegionDo regionDo = regionService.getRegionDoByPostCode(req.getPostCode());
        if (regionDo != null) {
            et.setArea(regionDo.getName());
        }
        et.setUpdateBy(userId);
        et.setUpdateTime(new Date());
        et.setBookDate(DateUtils.stringFormatToDate(req.getBookDate()));
        baseMapper.updateById(et);

        operateRecordDao.operateAddRecord(SysConstant.OPERATE_UPDATE_ORDER_DOOR, et.getId(), userId, 10);


        //再去更新子表
        List<OrderDoorPickProductDo> productDoList = orderDoorPickProductDao.selectList(new LambdaQueryWrapper<OrderDoorPickProductDo>()
                .eq(OrderDoorPickProductDo::getDoorId, et.getId()));
        for (int i = 0; i < req.getList().size(); i++) {
            if (i < productDoList.size()) {
                //更新
                OrderDoorPickProductDo pickProductDo = productDoList.get(i);
                pickProductDo.setProductId(req.getList().get(i).getProductId());
                pickProductDo.setCount(req.getList().get(i).getCount());
                pickProductDo.setLength(req.getList().get(i).getLength());
                pickProductDo.setWidth(req.getList().get(i).getWidth());
                pickProductDo.setHeight(req.getList().get(i).getHeight());
                pickProductDo.setWeight(req.getList().get(i).getWeight());
                orderDoorPickProductDao.updateById(pickProductDo);
            } else {
                //插入
                OrderDoorPickProductDo pickProductDo = new OrderDoorPickProductDo();
                BeanUtils.copyProperties(req.getList().get(i), pickProductDo);
                pickProductDo.setDoorId(et.getId());
                pickProductDo.setCreateTime(new Date());
                pickProductDo.setCreateBy(userId);
                orderDoorPickProductDao.insert(pickProductDo);
            }
        }
        //删除
        for (int i = req.getList().size(); i < productDoList.size(); i++) {
            orderDoorPickProductDao.deleteById(productDoList.get(i).getId());
        }
        productDoList = orderDoorPickProductDao.selectList(new LambdaQueryWrapper<OrderDoorPickProductDo>()
                .eq(OrderDoorPickProductDo::getDoorId, et.getId()));
        double[] sizeTemp = new double[4];
        for (OrderDoorPickProductDo orderDoorPickProductDo : productDoList) {
            sizeTemp = mShipPriceService.countSameSkuSizeNew(sizeTemp, orderDoorPickProductDo.getLength(), orderDoorPickProductDo.getWidth(), orderDoorPickProductDo.getHeight(), orderDoorPickProductDo.getWeight(), orderDoorPickProductDo.getCount());
        }
        this.setPrice(et, sizeTemp);
        baseMapper.updateById(et);
        return null;
    }


    private void setPrice(OrderDoorPickDo entityDo, double[] sizeTemp) {
        entityDo.setLength(sizeTemp[0]);
        entityDo.setWidth(sizeTemp[1]);
        entityDo.setHeight(sizeTemp[2]);
        entityDo.setWeight(sizeTemp[3]);
        QuotePriceRes doorPriceRes = quotePriceService.getDoorPrice(
                mRegionService.getStateIdByPostCode(entityDo.getPostCode()),
                sizeTemp,
                entityDo.getStorageId(),
                entityDo.getTrackId(),
                entityDo.getCompanyId()
        );
        if (doorPriceRes.getCode() == 200) {
            entityDo.setShipPrice(doorPriceRes.getPrice());
            entityDo.setPrice(0);
        } else {
            entityDo.setPrice(1);
        }
    }

    //编辑校验
    private void updateCheck(Object req) {

    }

    //做修改之前要执行的业务定制处理
    private void handlerUpdateBefore(OrderDoorPickDo entityDo, Long userId) {
        entityDo.setUpdateBy(userId);
        entityDo.setUpdateTime(new Date());
    }

    //做修改之后要执行的业务定制处理
    private Object handlerUpdateAfter(OrderDoorPickDo entityDo) {
        Object res = new Object();
        BeanUtils.copyProperties(entityDo, res);
        return res;
    }

    @Override
    public int delete(Long id, Long userId, Long companyId) {
        OrderDoorPickDo et = baseMapper.selectById(id);
        if (Objects.isNull(et)) {
            throw new BizException(SysConstant.No_Data);
        }
        if (!Objects.equals(companyId, et.getCompanyId())) {
            throw new BizException(SysConstant.NoPower);
        }
        if (!(StaticDict.Order_Door_Pick_Status.ToCheck.getValue().equals(et.getStatus()))) {
            throw new BizException(SysConstant.NoPower);
        }
        int i = baseMapper.deleteById(id);
        operateRecordDao.operateAddRecord(SysConstant.OPERATE_DELETE_ORDER_DOOR, et.getId(), userId, 10);
        return i;
    }

    //做删除之前要执行的业务定制处理
    private void handlerDeleteBefore(OrderDoorPickDo entityDo, Long userId) {
    }

    @Override
    public Object detail(Long id) {
        OrderDoorPickDo entityDo = baseMapper.selectById(id);
        if (entityDo == null) {
            throw new BizException(SysConstant.NoPower);
        }
        OrderDoorPickRes res = new OrderDoorPickRes();
        BeanUtils.copyProperties(entityDo, res);
        ShopDo shopDo = shopDao.selectById(entityDo.getShopId());
        if (shopDo != null) {
            res.setShopName(shopDo.getShopName());
        }
        CompanyDo companyDo = mCompanyDao.selectById(entityDo.getCompanyId());
        if (companyDo != null) {
            res.setCompanyCode(companyDo.getCompanyCode());
        }
        StorageDo storageDo = storageDao.selectById(entityDo.getStorageId());
        if (storageDo != null) {
            res.setStorageName(storageDo.getStorageName());
        }
        List<OrderDoorPickProductDo> productDoList = orderDoorPickProductDao.selectList(new LambdaQueryWrapper<OrderDoorPickProductDo>()
                .eq(OrderDoorPickProductDo::getDoorId, entityDo.getId()));

        List<OrderDoorPickProductRes> list = new ArrayList<>();
        for (OrderDoorPickProductDo productDo : productDoList) {
            OrderDoorPickProductRes productRes = new OrderDoorPickProductRes();
            BeanUtils.copyProperties(productDo, productRes);
            if (productDo.getProductId() == -1L) {
                productRes.setSku("未知商品");
            } else {
                ProductInfoDo productInfoDo = productInfoDao.selectObject(productDo.getProductId());
                if (productInfoDo != null) {
                    productRes.setSku(productInfoDo.getCommoditySku());
                    productRes.setCommoditySku(productInfoDo.getCommoditySku());
                    productRes.setProductName(productInfoDo.getProductName());
                }
            }
            list.add(productRes);
        }
        res.setList(list);

        List<OperateRes> operateList = operateRecordDao.getOperateList(entityDo.getId(), 10);
        res.setOperateResList(operateList);
        return res;
    }

    @Override
    public SingleResult pageInit(Long userId, Long companyId) {
        Map<String, Object> map = new HashMap<>();
        map.put("shopList", shopService.selectShopListInit(userId, companyId));
        map.put("storageList", storageService.getStorageList());

        List<Map<String, Object>> statusListMap = new ArrayList<>();
        for (StaticDict.Order_Door_Pick_Status value : StaticDict.Order_Door_Pick_Status.values()) {
            Map<String, Object> statusMap = new HashMap<>();
            statusMap.put("id", value.getValue());
            statusMap.put("value", value.getText());
            statusMap.put("count", 0);
            statusListMap.add(statusMap);
        }
        map.put("statusList", statusListMap);
        List<DicItemRes> doorTrackList = new ArrayList<>();
        doorTrackList.add(new DicItemRes(StaticDict.Track_Type.SagawaExpress.getValue(), StaticDict.Track_Type.SagawaExpress.getText()));
        doorTrackList.add(new DicItemRes(StaticDict.Track_Type.YamatoExpress.getValue(), StaticDict.Track_Type.YamatoExpress.getText()));
        doorTrackList.add(new DicItemRes(StaticDict.Track_Type.XinongExpress.getValue(), StaticDict.Track_Type.XinongExpress.getText()));
        map.put("doorTrackList", doorTrackList);

        return SingleResult.success(map);
    }

    @Override
    public List<OrderDoorPickPageRes> getList(Map<String, String> map) {
        QueryWrapper<OrderDoorPickDo> wrapper = queryBuild(map);
        List<OrderDoorPickDo> list = this.list(wrapper);
        return handlerListAfter(list);
    }


    @Override
    public PageResult getListPage(Map<String, String> map) {
        if (StringUtils.isBlank(map.get("companyId"))) {
            throw new BizException(SysConstant.Login_Error_Company);
        }
        QueryWrapper<OrderDoorPickDo> wrapper = queryBuild(map);
        IPage<OrderDoorPickDo> page = pageInit(map);
        page = this.page(page, wrapper);
        List<OrderDoorPickPageRes> resList = handlerListAfter(page.getRecords());
        PageResult result = new PageResult(resList, (int) page.getCurrent(), (int) page.getSize(), (int) page.getTotal(), (int) page.getPages());
        result.setMapInfo(countStatus(map));
        return result;
    }


    private Map countStatus(Map<String, String> map) {
        List<Map> result = new ArrayList<>();
        Map mapTotal = new HashMap();
        map.put("status", "");
        QueryWrapper<OrderDoorPickDo> wrapper = queryBuild(map);
        List<OrderDoorPickDo> list = this.list(wrapper);
        mapTotal.put("count", list.size());
        mapTotal.put("id", "");
        mapTotal.put("value", StringsUtil.createI18Message("全部"));
        result.add(mapTotal);

        Map<String, List<OrderDoorPickDo>> listMap = list.stream().collect(Collectors.groupingBy(OrderDoorPickDo::getStatus));

        for (StaticDict.Order_Door_Pick_Status value : StaticDict.Order_Door_Pick_Status.values()) {
            Map map1 = new HashMap();
            map.put("id", value.getValue());
            map.put("status", value.getValue());
            if (listMap.get(value.getValue()) != null) {
                map1.put("count", listMap.get(value.getValue()).size());
            } else {
                map1.put("count", 0);
            }
            map1.put("value", StringsUtil.createI18Message(value.getText()));
            result.add(map1);
        }
        Map map2 = new HashMap();
        map2.put("census", result);
        return map2;
    }

    //查询分页列表之后对列表数据的处理
    private List<OrderDoorPickPageRes> handlerListAfter(List<OrderDoorPickDo> list) {
        List<OrderDoorPickPageRes> result = new ArrayList<>();
        for (OrderDoorPickDo entityDo : list) {
            OrderDoorPickPageRes res = new OrderDoorPickPageRes();
            BeanUtils.copyProperties(entityDo, res);
            ShopDo shopDo = shopDao.selectById(entityDo.getShopId());
            if (shopDo != null) {
                res.setShopName(shopDo.getShopName());
            }
            CompanyDo companyDo = mCompanyDao.selectById(entityDo.getCompanyId());
            if (companyDo != null) {
                res.setCompanyCode(companyDo.getCompanyCode());
            }
            StorageDo storageDo = storageDao.selectById(entityDo.getStorageId());
            if (storageDo != null) {
                res.setStorageName(storageDo.getStorageName());
            }
            result.add(res);
        }
        return result;
    }

    private IPage<OrderDoorPickDo> pageInit(Map<String, String> map) {
        IPage<OrderDoorPickDo> page = new Page<>();
        page.setSize(StringUtils.isNotBlank(map.get("pageSize")) ? Long.parseLong(map.get("pageSize")) : 10);
        page.setCurrent(StringUtils.isNotBlank(map.get("current")) ? Long.parseLong(map.get("current")) : 1);
        return page;
    }

    private QueryWrapper<OrderDoorPickDo> queryBuild(Map<String, String> map) {
        QueryWrapper<OrderDoorPickDo> wrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(map.get("keyword"))) {
            wrapper.and(i -> i.like("door_no", map.get("keyword")).or().like("track_number", map.get("keyword")));
        }
        if (StringUtils.isNotBlank(map.get("companyId"))) {
            wrapper.eq("company_id", map.get("companyId"));
        }
        if (StringUtils.isNotBlank(map.get("shopId"))) {
            wrapper.eq("shop_id", map.get("shopId"));
        }
        if (StringUtils.isNotBlank(map.get("storageId"))) {
            wrapper.eq("storage_id", map.get("storageId"));
        }
        if (StringUtils.isNotBlank(map.get("status"))) {
            wrapper.eq("status", map.get("status"));
        }
        if (StringUtils.isNotBlank(map.get("beginTime"))) {
            wrapper.ge("create_time", map.get("beginTime"));
        }
        if (StringUtils.isNotBlank(map.get("endTime"))) {
            wrapper.lt("create_time", DateUtils.dateFormatToString(DateUtils.passingDate(map.get("endTime"), 1)));
        }
        wrapper.orderByDesc("id");
        return wrapper;
    }


    @Override
    public List<OrderOutMsgRes> getOrderMsgByTrackNumber(String trackNumber, String beginTime, String endTime, Long companyId) {
        //先去主表查 一单一包裹的
        List<OrderOutputDo> list = orderOutputDao.getListByTrackNumber(trackNumber, beginTime, endTime, companyId);

        //再去查商品信息
        List<OrderOutputProductDo> productDoList = new ArrayList<>();
        if (list.size() != 0) {
            List<Long> collect = list.stream().map(OrderOutputDo::getId).collect(Collectors.toList());
            productDoList = orderOutputProductDao.selectList(new LambdaQueryWrapper<OrderOutputProductDo>().in(OrderOutputProductDo::getOrderId, collect));
        }

        Map<Long, List<OrderOutputProductDo>> collect = productDoList.stream().collect(Collectors.groupingBy(OrderOutputProductDo::getOrderId));


        List<OrderOutMsgRes> resList = new ArrayList<>();
        for (OrderOutputDo et : list) {
            OrderOutMsgRes res = new OrderOutMsgRes();
            BeanUtils.copyProperties(et, res);

            List<OrderOutputProductDo> productDos = collect.get(et.getId());
            if (productDos == null) {
                continue;
            }
            List<OrderOutProductMsgRes> productMsgResList = new ArrayList<>();

            for (OrderOutputProductDo productDo : productDos) {
                OrderOutProductMsgRes productMsgRes = new OrderOutProductMsgRes();
                productMsgRes.setCount(productDo.getCount());
                productMsgRes.setProductId(productDo.getProductId());
                ProductInfoDo productInfoDo = productInfoDao.selectObject(productDo.getProductId());
                if (productInfoDo != null) {
                    productMsgRes.setWidth(productInfoDo.getWidth());
                    productMsgRes.setLength(productInfoDo.getLength());
                    productMsgRes.setHeight(productInfoDo.getHeight());
                    productMsgRes.setWeight(productInfoDo.getWeight());
                    productMsgRes.setProductName(productInfoDo.getProductName());
                    productMsgRes.setCommoditySku(productInfoDo.getCommoditySku());

                }

                productMsgResList.add(productMsgRes);
            }
            res.setList(productMsgResList);
            resList.add(res);
        }

        return resList;
    }


    /**
     * 截单
     */
    @Override
    public void cutPickOrder(FinishProblemOrderReq req, Long userId) {
        //截单正常收取所有费用  已审核 和预约成功 才可以截单 已审核截单 只收取预约费  预约成功截单 再加收快递费
        OrderDoorPickDo et = baseMapper.selectById(req.getId());
        if (et == null) {
            throw new BizException(SysConstant.No_Data);
        }
        if (!(StaticDict.Order_Door_Pick_Status.ToRegister.getValue().equals(et.getStatus()) || StaticDict.Order_Door_Pick_Status.Picked.getValue().equals(et.getStatus()))) {
            throw new BizException(SysConstant.NoPower);
        }
        et.setShipPrice(req.getShipPrice());
        et.setOldStatus(et.getStatus());
        et.setStatus(StaticDict.Order_Door_Pick_Status.Cutting.getValue());
        et.setUpdateTime(new Date());
        et.setUpdateBy(userId);
        baseMapper.updateById(et);
        operateRecordDao.operateAddRecord(SysConstant.OPERATE_CUTTING_ORDER_DOOR, et.getId(), userId, 10);

    }


}
